/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.flexengine.component;

import com.flexengine.engine.Priority;
import com.flexengine.input.InputManager;
import com.flexengine.scene.SceneBundle;
import com.flexengine.view.GameWindow;
import com.flexengine.view.Graphics;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Luann R. Athayde
 * @version 1.0
 * @since 1.0
 */
public class GamePanel extends GameComponent {

    private ArrayList<GameComponent> gameComponents;

    protected float transparence;
    protected Color backgroundColor;

    protected boolean border;
    protected Color borderColor;
    protected int borderSize;
    protected int roundRectWidth;
    protected int roundRectHeight;

    // -- Draggable options...
    protected volatile int mouseX, mouseY;
    protected volatile boolean draggable;
    protected volatile boolean dragging;
    protected volatile Point dragInitPoint;
    protected volatile Point dragPoint;
    protected volatile Rectangle dragArea;

    public GamePanel(String name, float x, float y, Dimension size) {
        this(name, x, y, size, true, Priority.NORMAL_PRIORITY);
    }

    public GamePanel(String name, float x, float y, Dimension size, boolean visible, Priority priority) {
        this.name = name;
        normalizePosition(x,y);
        this.size = size != null ? size : new Dimension();
        this.visible = visible;
        this.priority = priority;
        // -- game components...
        this.gameComponents = new ArrayList<>();
        // --
        transparence = 1f;
        backgroundColor = null;
        border = true;
        borderColor = BASIC_BORDER_COLOR;
        borderSize = 2;
        roundRectWidth = roundRectHeight = 0;
        // -- Draggable options...
        this.draggable = true;
        this.dragging = false;
        this.dragInitPoint = new Point();
        this.dragPoint = new Point();
        this.dragArea = new Rectangle(0, 0, this.size.width, this.size.height);
    }

    private void normalizePosition(float x, float y) {
        this.x = Math.abs(x);
        this.y = Math.abs(y);
        if( this.x>GameWindow.getInstance().getWidth()-getSize().getWidth() ) {
            this.x = (float)(GameWindow.getInstance().getWidth()-getSize().getWidth());
        }
        if( this.y>GameWindow.getInstance().getHeight()-getSize().getHeight()) {
            this.y = (float)(GameWindow.getInstance().getHeight()-getSize().getHeight());
        }
    }
    
    @Override
    public void init(SceneBundle bundle) {
        for (int i = 0; i < gameComponents.size(); i++) {
            GameComponent gc = gameComponents.get(i);
            gc.init(bundle);
        }
    }

    @Override
    public void update(Long time, Long totalTime) {
        mouseX = InputManager.getMouseX();
        mouseY = InputManager.getMouseY();
        for (int i = 0; i < gameComponents.size(); i++) {
            GameComponent tmp = gameComponents.get(i);
            // --
            float tmpX = tmp.getX();
            float tmpY = tmp.getY();
            tmp.setPosition(tmpX + x, tmpY + y);
            tmp.update(time, totalTime);
            tmp.setPosition(tmpX, tmpY);
        }

        if (draggable && visible) {
            if (InputManager.isMousePressed(InputManager.MOUSE_BUTTON1)
                    && mouseX >= x && mouseX <= x + dragArea.width
                    && mouseY >= y && mouseY <= y + dragArea.height) {
                if (!dragging) {
                    dragInitPoint.move((int) x, (int) y);
                    dragPoint.move(mouseX, mouseY);
                }
                dragging = true;
            } else if (!InputManager.isMousePressed(InputManager.MOUSE_BUTTON1)) {
                dragging = false;
            }
            if (dragging) {
                x = dragInitPoint.x + (mouseX - dragPoint.x);
                y = dragInitPoint.y + (mouseY - dragPoint.y);
                Dimension winSize = GameWindow.getInstance().getSize();
                Insets i = GameWindow.getInstance().getInsets();
                if (x <= i.left) {
                    x = i.left;
                } else if (x + size.width >= winSize.getWidth() - i.right) {
                    x = (float) (winSize.getWidth() - size.width - i.right);
                }
                if (y <= i.top) {
                    y = i.top;
                } else if (y + size.height >= winSize.getHeight() - i.bottom) {
                    y = (float) (winSize.getHeight() - size.height - i.bottom);
                }
            }
        }
    }

    @Override
    public void render(Graphics g) {
        if (visible) {
            if (backgroundColor != null) {
                g.setColor(backgroundColor);
                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparence));
                g.fillRoundRect((int) x, (int) y, size.width, size.height, roundRectWidth, roundRectHeight);
                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
            }
            for (int i = 0; i < gameComponents.size(); i++) {
                GameComponent tmp = gameComponents.get(i);
                if (tmp.isVisible()) {
                    float tmpX = tmp.getX();
                    float tmpY = tmp.getY();
                    tmp.setPosition(tmpX + x, tmpY + y);
                    tmp.render(g);
                    tmp.setPosition(tmpX, tmpY);
                }
            }
            drawBorder(g.create());
        }
    }

    public void drawBorder(Graphics g) {
        if (border) {
            g.setColor(borderColor);
            g.setStroke(new BasicStroke(borderSize));
            g.drawRoundRect((int) x, (int) y, size.width, size.height, roundRectWidth, roundRectHeight);
            g.setStroke(new BasicStroke(1));
        }
    }

    @Override
    public void end(SceneBundle bundle) {
        for (int i = 0; i < gameComponents.size(); i++) {
            GameComponent gc = gameComponents.get(i);
            gc.end(bundle);
        }
    }

    @Override
    public boolean isVisible() {
        return visible;
    }

    @Override
    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    @Override
    public Priority getPriority() {
        return priority;
    }

    @Override
    public void setPriority(Priority p) {
        this.priority = p;
    }

    public void add(GameComponent obj) {
        gameComponents.add(obj);
    }

    public GameComponent get(int index) {
        return gameComponents.get(index);
    }

    public GameComponent remove(int index) {
        return gameComponents.remove(index);
    }

    public boolean remove(GameComponent obj) {
        return gameComponents.remove(obj);
    }

    public boolean isEmpty() {
        return gameComponents.isEmpty();
    }

    public int size() {
        return gameComponents.size();
    }

    public void clear() {
        gameComponents.clear();
    }

    public List<GameComponent> getPanelComponents() {
        try {
            return (ArrayList) gameComponents.clone();
        } catch (Exception e) {
        }
        return null;
    }

    public List<GameComponent> getPanelComponents(Class s) {
        ArrayList list = new ArrayList();
        GameComponent tmp;
        for (int i = 0; i < gameComponents.size(); i++) {
            tmp = gameComponents.get(i);
            if (s.getName().equalsIgnoreCase(tmp.getClass().getName())) {
                list.add(tmp);
            }
        }
        return list;
    }

    public Color getBackgroundColor() {
        return backgroundColor;
    }

    public void setBackgroundColor(Color backgroundColor) {
        this.backgroundColor = backgroundColor;
    }

    public boolean hasBorder() {
        return border;
    }

    public Color getBorderColor() {
        return borderColor;
    }

    public int getBorderSize() {
        return borderSize;
    }
    
    public void setBorderSize(int borderSize) {
        this.borderSize = borderSize;
    }
    
    public void setBorder(boolean border) {
        this.border = border;
    }

    public void setBorderColor(Color borderColor) {
        this.borderColor = borderColor;
    }

    public Rectangle getDragArea() {
        return dragArea;
    }

    public void setDragArea(double x, double y, double width, double height) {
        this.dragArea.setBounds((int) x, (int) y, (int) width, (int) height);
    }

    public boolean isDraggable() {
        return draggable;
    }

    public void setDraggable(boolean draggable) {
        this.draggable = draggable;
    }

    public boolean isDragging() {
        return dragging;
    }

    public int getRoundRectHeight() {
        return roundRectHeight;
    }

    public int getRoundRectWidth() {
        return roundRectWidth;
    }

    public void setRoundRectHeight(int roundRectHeight) {
        this.roundRectHeight = roundRectHeight;
    }

    public void setRoundRectWidth(int roundRectWidth) {
        this.roundRectWidth = roundRectWidth;
    }

    public void setRoundRect(int roundRectHeight, int roundRectWidth) {
        setRoundRectHeight(roundRectHeight);
        setRoundRectWidth(roundRectWidth);
    }

    @Override
    public void setSize(Dimension size) {
        if (size != null) {
            this.size.setSize(size.width, size.height);
            roundRectWidth = roundRectHeight = size.height / 10;
        }
    }

    @Override
    public void setSize(double width, double height) {
        size.setSize(width, height);
        roundRectWidth = roundRectHeight = size.height / 10;
    }

    public void setTransparence(float transparence) {
        this.transparence = transparence;
    }

    public float getTransparence() {
        return transparence;
    }

}
